baubs git
src/formats/pen/decoder.ts fix/state-during-render-usePatternTransform (47e32ef8) Text, 5.04 KB
/**
* PEN Format Decoder
*
* This module contains the logic for decoding Brother PP1 PEN format embroidery files.
* The PEN format uses absolute coordinates shifted left by 3 bits, with flags in the low 3 bits.
*/
import type { DecodedPenStitch, DecodedPenData, PenColorBlock } from "./types";
// PEN format flags
const PEN_FEED_DATA = 0x01; // Bit 0: Jump stitch (move without stitching)
const PEN_CUT_DATA = 0x02; // Bit 1: Trim/cut thread command
const PEN_COLOR_END = 0x03; // Last stitch before color change
const PEN_DATA_END = 0x05; // Last stitch of entire pattern
/**
* Decode a single PEN stitch (4 bytes) into coordinates and flags
*
* @param bytes The byte array containing PEN data
* @param offset The offset in bytes to start reading from
* @returns Decoded stitch with coordinates and flag information
*/
export function decodePenStitch(
bytes: Uint8Array | number[],
offset: number,
): DecodedPenStitch {
const xLow = bytes[offset];
const xHigh = bytes[offset + 1];
const yLow = bytes[offset + 2];
const yHigh = bytes[offset + 3];
const xRaw = xLow | (xHigh << 8);
const yRaw = yLow | (yHigh << 8);
// Extract flags from low 3 bits
const xFlags = xRaw & 0x07;
const yFlags = yRaw & 0x07;
// Clear flags and shift right to get actual coordinates
const xClean = xRaw & 0xfff8;
const yClean = yRaw & 0xfff8;
// Convert to signed 16-bit
let xSigned = xClean;
let ySigned = yClean;
if (xSigned > 0x7fff) xSigned = xSigned - 0x10000;
if (ySigned > 0x7fff) ySigned = ySigned - 0x10000;
// Shift right by 3 to get actual coordinates
const x = xSigned >> 3;
const y = ySigned >> 3;
const isFeed = (yFlags & PEN_FEED_DATA) !== 0;
const isCut = (yFlags & PEN_CUT_DATA) !== 0;
const isColorEnd = xFlags === PEN_COLOR_END;
const isDataEnd = xFlags === PEN_DATA_END;
return {
x,
y,
xFlags,
yFlags,
isFeed,
isCut,
isColorEnd,
isDataEnd,
// Compatibility aliases
isJump: isFeed,
flags: (xFlags & 0x07) | (yFlags & 0x07),
};
}
/**
* Decode all stitches from PEN format bytes
*
* @param bytes PEN format byte array
* @returns Array of decoded stitches
*/
export function decodeAllPenStitches(
bytes: Uint8Array | number[],
): DecodedPenStitch[] {
if (bytes.length < 4 || bytes.length % 4 !== 0) {
throw new Error(
\\`Invalid PEN data size: ${bytes.length} bytes (must be multiple of 4)\\`,
);
}
const stitches: DecodedPenStitch[] = [];
for (let i = 0; i < bytes.length; i += 4) {
stitches.push(decodePenStitch(bytes, i));
}
return stitches;
}
/**
* Decode PEN format data into a complete pattern structure
*
* This function parses PEN bytes and extracts:
* - Individual stitches with coordinates and flags
* - Color blocks (groups of stitches using the same thread color)
* - Pattern bounds
*
* @param data PEN format byte array
* @returns Complete decoded pattern data
*/
export function decodePenData(data: Uint8Array): DecodedPenData {
const stitches = decodeAllPenStitches(data);
const colorBlocks: PenColorBlock[] = [];
let minX = Infinity;
let maxX = -Infinity;
let minY = Infinity;
let maxY = -Infinity;
let currentColorStart = 0;
let currentColor = 0;
for (let i = 0; i < stitches.length; i++) {
const stitch = stitches[i];
// Track bounds (exclude jump stitches)
if (!stitch.isFeed) {
minX = Math.min(minX, stitch.x);
maxX = Math.max(maxX, stitch.x);
minY = Math.min(minY, stitch.y);
maxY = Math.max(maxY, stitch.y);
}
// Check for color change or data end
if (stitch.isColorEnd) {
colorBlocks.push({
startStitchIndex: currentColorStart,
endStitchIndex: i,
colorIndex: currentColor,
// Compatibility aliases
startStitch: currentColorStart,
endStitch: i,
});
currentColor++;
currentColorStart = i + 1;
} else if (stitch.isDataEnd) {
// Final color block
if (currentColorStart <= i) {
colorBlocks.push({
startStitchIndex: currentColorStart,
endStitchIndex: i,
colorIndex: currentColor,
// Compatibility aliases
startStitch: currentColorStart,
endStitch: i,
});
}
break;
}
}
return {
stitches,
colorBlocks,
bounds: {
minX: minX === Infinity ? 0 : minX,
maxX: maxX === -Infinity ? 0 : maxX,
minY: minY === Infinity ? 0 : minY,
maxY: maxY === -Infinity ? 0 : maxY,
},
};
}
/**
* Get the color index for a stitch at the given index
*
* @param penData Decoded PEN pattern data
* @param stitchIndex Index of the stitch
* @returns Color index, or -1 if not found
*/
export function getStitchColor(
penData: DecodedPenData,
stitchIndex: number,
): number {
for (const block of penData.colorBlocks) {
if (
stitchIndex >= block.startStitchIndex &&
stitchIndex <= block.endStitchIndex
) {
return block.colorIndex;
}
}
return -1;
}
Served by rngit 1.3.3 - Generated in 0.03s